#include <QPainter>
#include <QPen>
#include "tetrix.h"
#include "ui_tetrix.h"
#include <string.h>

Tetrix::Tetrix(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Tetrix)
{
    ui->setupUi(this);
    //this->setMinimumSize(640,this->statusBar()->height() + 400 + this->menuBar()->height());
    //this->setMaximumSize(640,this->statusBar()->height() + 400 + this->menuBar()->height());

    this->setMinimumSize(640,410 + this->menuBar()->height());
    this->setMaximumSize(640,410 + this->menuBar()->height());

    this->ui->centralWidget->setMinimumSize(640,400);
    this->ui->centralWidget->setMaximumSize(640,400);

    _game_level = 1;
    init();
}

Tetrix::~Tetrix()
{
    delete ui;
}

void Tetrix::init()
{
    x = 5;
    y = -1; //?
    _lineRemoved = 0;

    for(int i = 0; i < TETRIX_HEIGHT; i++)
        for(int j = 0; j < TETRIX_WIDTH; j++)
            _board[i * TETRIX_WIDTH + j] = 0;

    for(int i = 0; i < TETRIX_HEIGHT; i++)
        _row_filled[i] = 0;

    for(int i = 0; i < TETRIX_WIDTH; i++)
        _col_height[i] = 0;

    this->ui->score->setNum(_lineRemoved);
}

TetrixPiece Tetrix::createTetrixPiece()
{
    static int pa0[3 * 2] = {1,0,1,1,0,1};//SPiece
    static int pa1[3 * 2] = {0,1,1,1,1,0};//ZPiece
    static int pa2[3 * 2] = {1,0,1,0,1,1};//LPiece
    static int pa3[3 * 2] = {0,1,0,1,1,1};//MirroredLPiece
    static int pa4[4 * 1] = {1,1,1,1};//IPiece
    static int pa5[2 * 3] = {1,1,1,0,1,0};//TPiece

    QTime t;
    int i = t.secsTo(QTime::currentTime());
    qsrand(i);
    int seq = qrand() % 6;

    if(seq == 0)
        return TetrixPiece(pa0,3,2,Qt::green);
    else if(seq == 1)
        return TetrixPiece(pa1,3,2,Qt::red);
    else if(seq == 2)
        return TetrixPiece(pa2,3,2,Qt::yellow);
    else if(seq == 3)
        return TetrixPiece(pa3,3,2,Qt::blue);
    else if(seq == 4)
	return TetrixPiece(pa4,4,1,Qt::black);
    else
        return TetrixPiece(pa5,2,3,Qt::magenta);
}


void Tetrix::restartTimer()
{
    _timer.stop();
    _timer.start(TIMER_TIMEOUT/_game_level,this);
}


void Tetrix::paintPiece(int x,int y,QPainter &painter,const TetrixPiece &piece)
{
    if(piece.size() <= 0)
        return;

    for(int row = 0; row < piece.height(); row++)
    {
        for(int col = 0; col < piece.width(); col++)
        {
            if(piece.isFilled(row * piece.width() + col)){
                painter.fillRect((x + col) * CELL_SIZE + 1,(y + row) * CELL_SIZE  + this->ui->menuBar->height() + 1,CELL_SIZE - 1,CELL_SIZE - 1,piece.color());
                //show current piece
                painter.fillRect(col * CELL_SIZE + 1 + 500,row * CELL_SIZE  + this->ui->menuBar->height() + 1 + 100,CELL_SIZE - 1,CELL_SIZE - 1,piece.color());
            }
        }
    }
}

void Tetrix::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void Tetrix::paintEvent(QPaintEvent *event)
{
    QMainWindow::paintEvent(event);

    QPen pen(Qt::DashLine);
    pen.setColor(Qt::gray);

    QPainter painter(this);
    painter.setPen(pen);

    this->ui->score->setNum(_lineRemoved);
    for(int i = 0; i <= TETRIX_HEIGHT; i++)
        painter.drawLine(0,CELL_SIZE * i + this->ui->menuBar->height(),TETRIX_WIDTH * CELL_SIZE,CELL_SIZE * i  + this->ui->menuBar->height());

    for(int i = 0; i <= TETRIX_WIDTH; i++)
        painter.drawLine(CELL_SIZE * i,0,CELL_SIZE * i,(TETRIX_HEIGHT + 1) * CELL_SIZE);

    pen.setColor(Qt::red);
    painter.setPen(pen);

    QColor c;
    QString text;
    for(int row = TETRIX_HEIGHT - 1; row >= 0; row--) {
        if(_row_filled[row] <= 0)
            break;

        for(int col = 0; col < TETRIX_WIDTH; col++) {
            if(_board[row * TETRIX_WIDTH + col] <= 0)
                continue;

            switch(_board[row * TETRIX_WIDTH + col]){
            case 1:{
                    c = Qt::green;
                    break;
                }
            case 2:{
                    c = Qt::red;
                    break;
                }
            case 3:{
                    c = Qt::yellow;
                    break;
                }
            case 4:{
                    c = Qt::blue;
                    break;
                }
            case 5:{
		    c = Qt::black;
                    break;
                }
            case 6:{
                    c = Qt::magenta;
                    break;
                }
            default:{
                   break;
               }
            }

            painter.fillRect(col * CELL_SIZE + 1,row * CELL_SIZE + 1 + this->ui->menuBar->height(),CELL_SIZE - 1,CELL_SIZE - 1,c);

            text.setNum(_board[row * TETRIX_WIDTH + col]);
            painter.drawText(col * CELL_SIZE + 10,row * CELL_SIZE + 10 + this->ui->menuBar->height(),text);

            text.setNum(_row_filled[row]);
            painter.drawText(TETRIX_WIDTH * CELL_SIZE,row * CELL_SIZE + 10  + this->ui->menuBar->height(),text);
        }
    }

    //draw current piece
    if(_piece.size() > 0)
        paintPiece(x,y,painter,_piece);
}


void Tetrix::timerEvent(QTimerEvent *event)
{
    if(event->timerId() == _timer.timerId()){
	if(y + _piece.height() >= TETRIX_HEIGHT || isCollision(0))
	    handleCollision();
	else{
	    y += 1;
	    update();
	}
    }
}

void Tetrix::keyPressEvent(QKeyEvent *event)
{
    switch(event->key()){
        case Qt::Key_Left:{	  
	    if(x > 0 && !isCollision(1)){
               x -= 1;
               update();
            }
            break;
        }
        case Qt::Key_Right:{
	    if(x +  _piece.width() < TETRIX_WIDTH && !isCollision(2)) {
               x += 1;
               update();
            }
            break;
        }
        case Qt::Key_Down:{
	    if(y + _piece.height() >= TETRIX_HEIGHT || isCollision(0)){
		handleCollision();
	    }
	    else{
		y++;
		update();
		restartTimer();
	    }
            break;
        }
        case Qt::Key_Up:{
           _piece.rotateLeft();

           if(x + _piece.width() >= TETRIX_WIDTH)
               x = TETRIX_WIDTH - _piece.width();

           update();
           break;
       }

        default:
            QMainWindow::keyPressEvent(event);
        }
}

void Tetrix::showNextPiece()
{
    x = 5;
    y = 0;
    _piece = Tetrix::createTetrixPiece();
}

QPoint Tetrix::collisionDetect()
{
    QPoint p;
    for(int col = x; col < x + _piece.width(); col++){
        if(y + _piece.height() + _col_height[col] < TETRIX_HEIGHT)
            continue;

        for(int row = _piece.height() - 1; row >= 0; row--){
            if(_piece.isFilled(row,col) && y + row > p.y()){
                p.setX(col);
                p.setY(row);
                break;
            }
        }
    }
    return p;
}

bool Tetrix::isCollision(int direction)
{
    int pos_x = x;
    int pos_y = y;

    if(direction == 0) //down
	pos_y++;
    else if(direction == 1)//left
	pos_x--;
    else if(direction == 2)//right
	pos_x++;

    for(int row = 0; row < _piece.height();row++){
	for(int col = 0; col < _piece.width(); col++){
	    if(
	       _piece.isFilled(row,col)
	       &&
	       _board[TETRIX_WIDTH * (pos_y + row) + pos_x + col] > 0
	     )
                return true;
	}
    }
    return false;
}

void Tetrix::handleCollision()
{
    //fill board by piece's value
    for(int row = 0; row < _piece.height(); row++){
        for(int col = 0; col < _piece.width(); col++){
            if(_piece.isFilled(row,col)){
                _row_filled[y + row]++;

                int value = 0;
                if(_piece.color() == Qt::green)
                    value = 1;
                else if(_piece.color() == Qt::red)
                    value = 2;
                else if(_piece.color() == Qt::yellow)
                    value = 3;
                else if(_piece.color() == Qt::blue)
                    value = 4;
		else if(_piece.color() == Qt::black)
                    value = 5;
                else if(_piece.color() == Qt::magenta)
                    value = 6;

                _board[(y + row) * TETRIX_WIDTH + (x + col)] = value;
            }
        }
    }

    //remove completed line
    for(int row = TETRIX_HEIGHT - 1;row >= 0;row--){
        if(_row_filled[row] >= TETRIX_WIDTH){
            this->_lineRemoved++;

	    for(int i = row * TETRIX_WIDTH - 1; i >= 0; i--){
		_board[i + TETRIX_WIDTH] = _board[i];
	    }
	    for(int i = 0; i < TETRIX_WIDTH; i++)
		_board[i] = 0;

            for(int i = row; i > 0; i--)
                _row_filled[i] = _row_filled[i - 1];

            _row_filled[0] = 0;
	}
    }

    _piece.clean();
    update();

    if(_row_filled[0] > 0){ //end game
        this->ui->statusLabel->setText(QString("Game Over"));
        this->_timer.stop();
        _piece.clean();
    }
    else{   //continue game
        showNextPiece();
    }
}


void Tetrix::on_actionStartGame_triggered()
{
    init();

    _piece = Tetrix::createTetrixPiece();

    _timer.stop();

    _timer.start(TIMER_TIMEOUT/_game_level,this);
}

void Tetrix::on_actionExit_triggered()
{
    QApplication::exit();
}

void Tetrix::on_actionLevel_1_triggered()
{
    _game_level = 1;
    on_actionStartGame_triggered();
}

void Tetrix::on_actionLevel_2_triggered()
{
    if(_game_level != 2){
        _game_level = 2;
        on_actionStartGame_triggered();
    }
}

void Tetrix::on_actionLevel_3_triggered()
{
    if(_game_level != 3){
        _game_level = 3;
        on_actionStartGame_triggered();
    }
}

void Tetrix::on_actionLevel_4_triggered()
{
    if(_game_level != 4){
        _game_level = 4;
        on_actionStartGame_triggered();
    }
}

void Tetrix::on_actionLevel_5_triggered()
{
    if(_game_level != 5){
        _game_level = 5;
        on_actionStartGame_triggered();
    }
}

void Tetrix::on_actionLevel_6_triggered()
{
    if(_game_level != 6){
        _game_level = 6;
        on_actionStartGame_triggered();
    }
}
